// +build !linux

package main

import (
	"fmt"
	"syscall"
	"unsafe"
)

// Crypt 接口.
type Crypt struct {
	MIFreeSafeHandle    *syscall.LazyProc
	MIGetDecryptDataLen *syscall.LazyProc
	MIGetEncryptDataLen *syscall.LazyProc
	MIGetSafeHandle     *syscall.LazyProc
	MILoad              *syscall.LazyProc
	MITransDecrypt      *syscall.LazyProc
	MITransEncrypt      *syscall.LazyProc
}

var lib *syscall.LazyDLL
var c *Crypt

func init() {
	lib = syscall.NewLazyDLL("crypto64.dll")
	c = &Crypt{
		MIGetSafeHandle:     lib.NewProc("MIGetSafeHandle"),
		MIFreeSafeHandle:    lib.NewProc("MIFreeSafeHandle"),
		MIGetDecryptDataLen: lib.NewProc("MIGetDecryptDataLen"),
		MIGetEncryptDataLen: lib.NewProc("MIGetEncryptDataLen"),
		MILoad:              lib.NewProc("MILoad"),
		MITransDecrypt:      lib.NewProc("MITransDecrypt"),
		MITransEncrypt:      lib.NewProc("MITransEncrypt"),
	}
}

// GetSafeHandle 获取对象.
func GetSafeHandle() unsafe.Pointer {
	h, _, _ := c.MIGetSafeHandle.Call()
	c.MILoad.Call(uintptr(0), 0, h)

	return unsafe.Pointer(h)
}

// FreeSafeHandle 释放.
func FreeSafeHandle(h unsafe.Pointer) {
	c.MIFreeSafeHandle.Call(uintptr(h))
}

// TransEncrypt 加密.
func TransEncrypt(h unsafe.Pointer, src []byte) []byte {
	var iLen int32
	var srcLen int = len(src)
	c.MIGetEncryptDataLen.Call(uintptr(unsafe.Pointer(&iLen)), uintptr(unsafe.Pointer(&src[0])), uintptr(srcLen), uintptr(h))

	// 加密.
	buf := make([]byte, iLen)
	c.MITransEncrypt.Call(uintptr(unsafe.Pointer(&buf[0])), uintptr(iLen), uintptr(unsafe.Pointer(&src[0])), uintptr(srcLen), uintptr(h))

	return buf
}

// TransDecrypt 解密.
func TransDecrypt(h unsafe.Pointer, src []byte) ([]byte, error) {
	dstLen := len(src)
	var iDLen int32
	c.MIGetDecryptDataLen.Call(uintptr(unsafe.Pointer(&iDLen)), uintptr(unsafe.Pointer(&src[0])), uintptr(dstLen), uintptr(h))

	// fmt.Println("get decrypt len:", iDLen)

	if iDLen > 100000 || iDLen < 0 {
		return nil, fmt.Errorf("get descrypt datalen invalid: %d", iDLen)
	}

	// 再解密.
	newSrc := make([]byte, iDLen)
	r1, _, _ := c.MITransDecrypt.Call(uintptr(unsafe.Pointer(&newSrc[0])), uintptr(iDLen), uintptr(unsafe.Pointer(&src[0])), uintptr(dstLen), uintptr(h))
	var err error = nil
	if int(r1) != 0 {
		err = fmt.Errorf("MITransDecrypt fail, iLen:%d ret:%d", iDLen, int(r1))
	}
	return newSrc, err
}
